package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

/**
- [飞雪无情_unsafe_pointer](https://www.flysnow.org/2017/07/06/go-in-action-unsafe-pointer.html)
- unsafe.Pointer 是一种全能型指针，可以包含任意类型的地址
unsafe.Pointer的4个规则。

任何指针都可以转换为unsafe.Pointer
unsafe.Pointer可以转换为任何指针
uintptr可以转换为unsafe.Pointer
unsafe.Pointer可以转换为uintptr

- 使用场景：
	- 底层类型相同的数组之前的转换
	- sync/atomic包中的一些函数时
	- 还有访问Struct的私有字段时

*/

func main() {
	intConversionFloat()
	uintprtFunc()
}

func intConversionFloat() {
	i := 10
	ip := &i

	fmt.Printf("Type:%s\n", reflect.TypeOf(i))
	var fp *float64 = (*float64)(unsafe.Pointer(ip))
	fmt.Println(&i)

	*fp = *fp * 3
	fmt.Printf("Type:%s\n", reflect.TypeOf(i))
	fmt.Println(fp)
}

//指针转换为uintptr后可以进行偏移量计算
func uintprtFunc() {
	u := new(user)  // new创建的是指针类型值，是指向内存中的地址，使用这个值要用(*)解引用
	fmt.Println(*u) // name 位于结构体第一个字段，所以不用偏移，可以直接取到并赋值

	pName := (*string)(unsafe.Pointer(u))
	*pName = "张三"

	//age 是第二个字段，需要将user指针转换为 uintptr，然后进行偏移运算获取pAge指针
	pAge := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(u)) + unsafe.Offsetof(u.age)))
	*pAge = 20

	fmt.Println(*u)
}

type user struct {
	name string
	age  int
}
